#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
构建管理器
负责实际的编译过程和目标构建
"""

import os
import logging
from pathlib import Path
from typing import List, Dict, Optional
from SCons.Script import *
from SCons.Script import Copy
from target_registry import BuildTarget, TargetType, TargetRegistry

class BuildManager:
    """构建管理器"""

    def __init__(self, env):
        """
        初始化构建管理器

        Args:
            env: SCons环境对象
        """
        self.env = env
        self.built_targets = {}  # 已构建的目标缓存
        self.target_registry = None
        self.prebuilt_commands = {}  # 预编译库Command缓存，避免重复创建

        # 默认输出目录 - 中间文件
        self.default_intermediate_dirs = {
            TargetType.EXECUTABLE: "out/intermediate/bin",
            TargetType.SHARED_LIBRARY: "out/intermediate/lib",
            TargetType.STATIC_LIBRARY: "out/intermediate/lib",
            TargetType.OBJECT_FILES: "out/intermediate/obj",
            TargetType.HEADER_LIBRARY: "out/intermediate/headers",
            TargetType.PROTO_LIBRARY: "out/intermediate/lib"
        }

        # 最终发布目录
        self.default_release_dirs = {
            TargetType.EXECUTABLE: "out/release",
            TargetType.SHARED_LIBRARY: "out/release",
            TargetType.STATIC_LIBRARY: "out/release",
            TargetType.OBJECT_FILES: "out/release",
            TargetType.HEADER_LIBRARY: "out/release/include",
            TargetType.PROTO_LIBRARY: "out/release/include"
        }

    def set_target_registry(self, registry: TargetRegistry):
        """设置目标注册表"""
        self.target_registry = registry

    def build_target(self, target_name: str):
        """
        构建指定目标

        Args:
            target_name: 目标名称

        Returns:
            构建的节点列表
        """
        if not self.target_registry:
            raise RuntimeError("目标注册表未设置")

        target = self.target_registry.get_target(target_name)
        if not target:
            raise ValueError(f"目标 '{target_name}' 不存在")

        # 先构建依赖目标
        dependencies = self.target_registry.resolve_dependencies(target_name)
        for dep_name in dependencies:
            if dep_name not in self.built_targets:
                self.build_target(dep_name)

        # 构建当前目标
        if target_name not in self.built_targets:
            built_target = self._build_single_target(target)
            self.built_targets[target_name] = built_target

            # 展平节点列表
            if isinstance(built_target, list):
                return built_target
            else:
                return [built_target]
        else:
            built_target = self.built_targets[target_name]
            if isinstance(built_target, list):
                return built_target
            else:
                return [built_target]

    def build_all_targets(self):
        """构建所有目标"""
        if not self.target_registry:
            raise RuntimeError("目标注册表未设置")

        all_targets = self.target_registry.get_all_targets()
        for target_name in all_targets:
            self.build_target(target_name)

    def _build_single_target(self, target: BuildTarget):
        """
        构建单个目标

        Args:
            target: 编译目标

        Returns:
            SCons构建结果
        """
        # 创建目标专用环境
        target_env = self.env.Clone()

        # 设置编译选项
        self._setup_target_environment(target_env, target)

        # 确定中间文件输出目录
        intermediate_dir = target.output_dir or self.default_intermediate_dirs.get(target.target_type, "out/intermediate")
        os.makedirs(intermediate_dir, exist_ok=True)

        # 确定最终发布目录
        release_dir = self.default_release_dirs.get(target.target_type, "out/release")
        os.makedirs(release_dir, exist_ok=True)

        # 根据目标类型进行构建
        if target.target_type == TargetType.EXECUTABLE:
            return self._build_executable(target_env, target, intermediate_dir, release_dir)
        elif target.target_type == TargetType.SHARED_LIBRARY:
            return self._build_shared_library(target_env, target, intermediate_dir, release_dir)
        elif target.target_type == TargetType.STATIC_LIBRARY:
            return self._build_static_library(target_env, target, intermediate_dir, release_dir)
        elif target.target_type == TargetType.OBJECT_FILES:
            return self._build_object_files(target_env, target, intermediate_dir, release_dir)
        elif target.target_type == TargetType.PREBUILT_STATIC_LIBRARY:
            return self._build_prebuilt_static_library(target_env, target, intermediate_dir, release_dir)
        elif target.target_type == TargetType.PREBUILT_SHARED_LIBRARY:
            return self._build_prebuilt_shared_library(target_env, target, intermediate_dir, release_dir)
        elif target.target_type == TargetType.HEADER_LIBRARY:
            return self._build_header_library(target_env, target, intermediate_dir, release_dir)
        elif target.target_type == TargetType.PROTO_LIBRARY:
            return self._build_proto_library(target_env, target, intermediate_dir, release_dir)
        else:
            raise ValueError(f"不支持的目标类型: {target.target_type}")

    def _setup_target_environment(self, env, target: BuildTarget):
        """
        设置目标编译环境

        Args:
            env: SCons环境
            target: 编译目标
        """
        # 添加头文件搜索路径
        if target.include_paths:
            env.Append(CPPPATH=target.include_paths)

        # 添加库搜索路径
        if target.lib_paths:
            env.Append(LIBPATH=target.lib_paths)

        # 添加链接库（兼容性处理）

        # 添加预处理宏定义
        if target.defines:
            # 处理宏定义格式
            processed_defines = []
            for define in target.defines:
                if isinstance(define, tuple) and len(define) == 2:
                    # 元组格式: (name, value)
                    name, value = define
                    # 如果值是字符串且包含引号，保持原样
                    if isinstance(value, str) and value.startswith('"') and value.endswith('"'):
                        # 对于字符串值，使用字典格式让SCons正确处理引号
                        processed_defines.append({name: value})
                    else:
                        processed_defines.append((name, value))
                else:
                    # 字符串格式: 直接使用
                    processed_defines.append(define)

            env.Append(CPPDEFINES=processed_defines)

        # 添加编译选项
        if target.cflags:
            env.Append(CCFLAGS=target.cflags)

        if target.cxxflags:
            env.Append(CXXFLAGS=target.cxxflags)

        # 添加链接选项
        if target.ldflags:
            env.Append(LINKFLAGS=target.ldflags)

        # 添加依赖目标的库
        self._add_dependency_libs(env, target)

    def _add_dependency_libs(self, env, target: BuildTarget):
        """
        添加依赖目标的库（支持传递依赖）

        Args:
            env: SCons环境
            target: 编译目标
        """
        logging.info(f"Processing dependencies for target: {target.name}")
        logging.info(f"Target dependencies: {target.dependencies}")
        logging.info(f"Target static_libs: {target.static_libs}")
        logging.info(f"Target shared_libs: {target.shared_libs}")
        visited = set()  # 防止循环依赖
        self._add_dependency_libs_recursive(env, target, visited)

    def _add_dependency_libs_recursive(self, env, target: BuildTarget, visited: set):
        """
        递归添加依赖目标的库

        Args:
            env: SCons环境
            target: 编译目标
            visited: 已访问的目标集合，防止循环依赖
        """
        if target.name in visited:
            return
        visited.add(target.name)

        # 处理直接指定的库依赖
        self._add_direct_libs(env, target)

        # 处理依赖目标
        for dep_name in target.dependencies:
            dep_target = self.target_registry.get_target(dep_name)
            if dep_target:
                if dep_target.target_type in [TargetType.STATIC_LIBRARY, TargetType.SHARED_LIBRARY]:
                    # 添加依赖库的输出目录到库搜索路径
                    if dep_target.output_dir:
                        dep_output_dir = dep_target.output_dir
                    else:
                        # 使用新的目标特定目录结构
                        dep_output_dir = os.path.join("out/intermediate/lib", dep_target.name)
                    env.Append(LIBPATH=[dep_output_dir])

                    # 添加依赖库名
                    env.Append(LIBS=[dep_name])

                elif dep_target.target_type in [TargetType.PREBUILT_STATIC_LIBRARY, TargetType.PREBUILT_SHARED_LIBRARY]:
                    # 处理预编译库
                    self._add_prebuilt_lib(env, dep_target)

                elif dep_target.target_type == TargetType.HEADER_LIBRARY:
                    # 处理头文件库：确保头文件库先被构建
                    logging.info(f"Processing HEADER_LIBRARY dependency: {dep_target.name}")
                    self.build_target(dep_target.name)

                    # 添加头文件库的导出路径到包含路径
                    if dep_target.export_include_paths:
                        export_paths = []
                        for path in dep_target.export_include_paths:
                            if os.path.isabs(path):
                                export_paths.append(path)
                            else:
                                # 相对于依赖库的Module目录
                                abs_path = os.path.join(dep_target.module_path, path)
                                export_paths.append(abs_path)
                        env.Append(CPPPATH=export_paths)
                        logging.info(f"Added header library include paths: {export_paths}")

                elif dep_target.target_type == TargetType.PROTO_LIBRARY:
                    # 处理proto库：确保proto库先被构建，并添加生成的头文件路径
                    logging.info(f"Processing PROTO_LIBRARY dependency: {dep_target.name}")
                    self.build_target(dep_target.name)

                    # 使用proto_support自动获取包含路径
                    proto_gensrc_dir = os.path.join("out/intermediate/lib", dep_target.name)
                    proto_support = env.get('PROTO_SUPPORT')
                    if proto_support and hasattr(dep_target, 'proto_files') and dep_target.proto_files:
                        proto_include_paths = proto_support.get_proto_include_paths(proto_gensrc_dir, dep_target.proto_files)
                        for include_path in proto_include_paths:
                            if include_path not in env['CPPPATH']:
                                env.Append(CPPPATH=[include_path])
                                logging.info(f"Added proto include path: {include_path}")
                    else:
                        # 回退到基本的gensrc目录
                        env.Append(CPPPATH=[proto_gensrc_dir])
                        logging.info(f"Added proto include path: {proto_gensrc_dir}")
                    
                    # 检查已构建的proto库信息，添加生成头文件路径
                    if dep_target.name in self.built_targets:
                        built_info = self.built_targets[dep_target.name]
                        if 'generated_headers' in built_info:
                            for header_file in built_info['generated_headers']:
                                header_dir = os.path.dirname(header_file)
                                if header_dir not in env['CPPPATH']:
                                    env.Append(CPPPATH=[header_dir])
                                    logging.info(f"Added proto header directory: {header_dir}")
                        # 同时添加gensrc_dir，确保能找到所有子目录的头文件
                        if 'gensrc_dir' in built_info:
                            gensrc_dir = built_info['gensrc_dir']
                            if gensrc_dir not in env['CPPPATH']:
                                env.Append(CPPPATH=[gensrc_dir])
                                logging.info(f"Added proto gensrc directory: {gensrc_dir}")
                        # 添加所有导出的包含路径
                        if 'export_include_paths' in built_info:
                            for export_path in built_info['export_include_paths']:
                                if export_path not in env['CPPPATH']:
                                    env.Append(CPPPATH=[export_path])
                                    logging.info(f"Added proto export include path: {export_path}")

                    # 添加proto静态库到链接库列表
                    env.Append(LIBPATH=[proto_gensrc_dir])
                    env.Append(LIBS=[dep_target.name])
                    logging.info(f"Added proto static library: {dep_target.name}")

                    # 链接protobuf库
                    env.Append(LIBS=['protobuf'])
                    logging.info(f"Added protobuf library for proto dependency: {dep_target.name}")

                # 添加依赖库的导出头文件路径到当前目标的头文件搜索路径
                if dep_target.export_include_paths:
                    # 将相对路径转换为绝对路径
                    export_paths = []
                    for path in dep_target.export_include_paths:
                        if os.path.isabs(path):
                            export_paths.append(path)
                        else:
                            # 相对于依赖库的Module目录
                            abs_path = os.path.join(dep_target.module_path, path)
                            export_paths.append(abs_path)
                    env.Append(CPPPATH=export_paths)

                # 递归处理传递依赖
                self._add_dependency_libs_recursive(env, dep_target, visited)

    def _add_direct_libs(self, env, target: BuildTarget):
        """
        添加目标直接指定的库依赖

        Args:
            env: SCons环境
            target: 编译目标
        """
        # 处理静态库
        all_static_libs = target.static_libs[:]

        for lib_name in all_static_libs:
            dep_target = self.target_registry.get_target(lib_name)
            if dep_target:
                if dep_target.target_type == TargetType.STATIC_LIBRARY:
                    # 确保依赖库先被构建
                    self.build_target(dep_target.name)
                    # 添加静态库的输出目录到库搜索路径
                    dep_output_dir = os.path.join("out/intermediate/lib", dep_target.name)
                    env.Append(LIBPATH=[dep_output_dir])
                    env.Append(LIBS=[lib_name])
                elif dep_target.target_type == TargetType.PREBUILT_STATIC_LIBRARY:
                    self._add_prebuilt_lib(env, dep_target)
                elif dep_target.target_type == TargetType.PROTO_LIBRARY:
                    # 处理proto库：确保proto库先被构建，并添加生成的头文件路径
                    logging.info(f"Processing PROTO_LIBRARY static lib: {dep_target.name}")
                    self.build_target(dep_target.name)

                    # 使用proto_support自动获取包含路径
                    proto_gensrc_dir = os.path.join("out/intermediate/lib", dep_target.name)
                    proto_support = env.get('PROTO_SUPPORT')
                    if proto_support and hasattr(dep_target, 'proto_files') and dep_target.proto_files:
                        proto_include_paths = proto_support.get_proto_include_paths(proto_gensrc_dir, dep_target.proto_files)
                        for include_path in proto_include_paths:
                            if include_path not in env['CPPPATH']:
                                env.Append(CPPPATH=[include_path])
                                logging.info(f"Added proto include path: {include_path}")
                    else:
                        # 回退到基本的gensrc目录
                        env.Append(CPPPATH=[proto_gensrc_dir])
                        logging.info(f"Added proto include path: {proto_gensrc_dir}")

                    # 检查已构建的proto库信息，添加生成头文件路径
                    if dep_target.name in self.built_targets:
                        built_info = self.built_targets[dep_target.name]
                        if 'generated_headers' in built_info:
                            for header_file in built_info['generated_headers']:
                                header_dir = os.path.dirname(header_file)
                                if header_dir not in env['CPPPATH']:
                                    env.Append(CPPPATH=[header_dir])
                                    logging.info(f"Added proto header directory: {header_dir}")
                        # 同时添加gensrc_dir，确保能找到所有子目录的头文件
                        if 'gensrc_dir' in built_info:
                            gensrc_dir = built_info['gensrc_dir']
                            if gensrc_dir not in env['CPPPATH']:
                                env.Append(CPPPATH=[gensrc_dir])
                                logging.info(f"Added proto gensrc directory: {gensrc_dir}")
                        # 添加所有导出的包含路径
                        if 'export_include_paths' in built_info:
                            for export_path in built_info['export_include_paths']:
                                if export_path not in env['CPPPATH']:
                                    env.Append(CPPPATH=[export_path])
                                    logging.info(f"Added proto export include path: {export_path}")

                    # 添加proto静态库到链接库列表
                    env.Append(LIBPATH=[proto_gensrc_dir])
                    env.Append(LIBS=[dep_target.name])
                    logging.info(f"Added proto static library: {dep_target.name}")

                    # 链接protobuf库
                    env.Append(LIBS=['protobuf'])
                    logging.info(f"Added protobuf library for proto static lib: {dep_target.name}")

        # 处理动态库
        for lib_name in target.shared_libs:
            dep_target = self.target_registry.get_target(lib_name)
            if dep_target:
                if dep_target.target_type == TargetType.SHARED_LIBRARY:
                    # 确保依赖库先被构建
                    self.build_target(dep_target.name)
                    # 添加动态库的输出目录到库搜索路径
                    dep_output_dir = os.path.join("out/intermediate/lib", dep_target.name)
                    env.Append(LIBPATH=[dep_output_dir])
                    env.Append(LIBS=[lib_name])
                elif dep_target.target_type == TargetType.PREBUILT_SHARED_LIBRARY:
                    self._add_prebuilt_lib(env, dep_target)

    def _add_prebuilt_lib(self, env, dep_target: BuildTarget):
        """
        添加预编译库

        Args:
            env: SCons环境
            dep_target: 预编译库目标
        """
        # 确保预编译库的marker文件被构建
        if dep_target.name not in self.built_targets:
            built_target = self._build_single_target(dep_target)
            self.built_targets[dep_target.name] = built_target

        if dep_target.library_path:
            # 添加预编译库文件的目录到库搜索路径
            lib_dir = os.path.dirname(dep_target.library_path)
            if lib_dir:
                env.Append(LIBPATH=[lib_dir])

            # 对于静态库，直接使用完整路径避免链接器选择动态库
            if dep_target.target_type == TargetType.PREBUILT_STATIC_LIBRARY:
                # 静态库使用完整路径
                full_lib_path = os.path.join(dep_target.module_path, dep_target.library_path)

                # 静态库使用完整路径
                env.Append(LIBS=[File(full_lib_path)])
            else:
                # 动态库使用库名
                lib_file = os.path.basename(dep_target.library_path)
                # 移除lib前缀和扩展名来获取库名
                if lib_file.startswith('lib'):
                    lib_name = lib_file[3:]  # 移除'lib'前缀
                    if '.' in lib_name:
                        lib_name = lib_name.split('.')[0]  # 移除扩展名
                    env.Append(LIBS=[lib_name])
                else:
                    # 如果没有lib前缀，直接使用文件名（去掉扩展名）
                    if '.' in lib_file:
                        lib_name = lib_file.split('.')[0]
                    else:
                        lib_name = lib_file
                    env.Append(LIBS=[lib_name])

    def _collect_dependency_export_paths(self, target: BuildTarget) -> List[str]:
        """
        递归收集所有依赖库的export_include_paths

        Args:
            target: 编译目标

        Returns:
            所有依赖库的export_include_paths列表
        """
        collected_paths = []
        visited = set()
        self._collect_dependency_export_paths_recursive(target, collected_paths, visited)
        return collected_paths

    def _collect_dependency_export_paths_recursive(self, target: BuildTarget, collected_paths: List[str], visited: set):
        """
        递归收集依赖库的export_include_paths

        Args:
            target: 编译目标
            collected_paths: 收集到的路径列表
            visited: 已访问的目标集合，防止循环依赖
        """
        if target.name in visited:
            return
        visited.add(target.name)

        for dep_name in target.dependencies:
            dep_target = self.target_registry.get_target(dep_name)
            if dep_target:
                # 收集依赖库的export_include_paths
                if dep_target.export_include_paths:
                    for path in dep_target.export_include_paths:
                        if os.path.isabs(path):
                            abs_path = path
                        else:
                            # 相对于依赖库的Module目录
                            abs_path = os.path.join(dep_target.module_path, path)

                        # 避免重复添加
                        if abs_path not in collected_paths:
                            collected_paths.append(abs_path)

                # 递归处理传递依赖
                self._collect_dependency_export_paths_recursive(dep_target, collected_paths, visited)

    def _build_executable(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        构建可执行文件

        Args:
            env: SCons环境
            target: 编译目标
            intermediate_dir: 中间文件目录
            release_dir: 最终发布目录

        Returns:
            SCons构建结果
        """
        # 添加依赖库（包括proto库的特殊处理）
        self._add_dependency_libs(env, target)
        
        # 收集依赖库的export_include_paths并合并到当前目标
        dependency_export_paths = self._collect_dependency_export_paths(target)
        target.export_include_paths.extend(dependency_export_paths)
        
        # 将依赖库的export_include_paths添加到编译环境
        for include_path in dependency_export_paths:
            env.Append(CPPPATH=[include_path])

        # 为可执行文件创建专用的目录结构
        target_dir = os.path.join("out/intermediate/bin", target.name)
        target_intermediate_dir = os.path.join(target_dir, "objs")
        os.makedirs(target_intermediate_dir, exist_ok=True)

        # 编译目标文件到指定目录
        objects = []
        # 编译主要源文件
        for source in target.sources:
            source_name = os.path.splitext(os.path.basename(source))[0]
            obj_path = os.path.join(target_intermediate_dir, f"{source_name}.o")
            obj = env.Object(target=obj_path, source=source)
            objects.append(obj)

        # 收集预编译库的marker文件作为依赖项
        prebuilt_markers = []
        all_libs = target.static_libs + target.shared_libs
        for lib_name in all_libs:
            dep_target = self.target_registry.get_target(lib_name)
            if dep_target and dep_target.target_type in [TargetType.PREBUILT_STATIC_LIBRARY, TargetType.PREBUILT_SHARED_LIBRARY]:
                # 直接构建预编译库的marker文件
                built_target = self._build_single_target(dep_target)
                if isinstance(built_target, list):
                    prebuilt_markers.extend(built_target)
                else:
                    prebuilt_markers.append(built_target)
                # 更新built_targets记录
                self.built_targets[dep_target.name] = built_target

        # 中间文件路径，放在目标目录下
        intermediate_path = os.path.join(target_dir, target.name)
        # 最终发布路径
        release_path = os.path.join(release_dir, target.name)

        # 构建可执行文件到中间目录
        program = env.Program(target=intermediate_path, source=objects)

        # 确保预编译库的marker文件先被构建
        for marker in prebuilt_markers:
            env.Depends(program, marker)

        # 拷贝到发布目录
        copy_cmd = env.Command(release_path, intermediate_path, Copy("$TARGET", "$SOURCE"))

        # 返回所有相关节点
        return [program, copy_cmd]

    def _build_shared_library(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        构建动态库

        Args:
            env: SCons环境
            target: 编译目标
            intermediate_dir: 中间文件目录
            release_dir: 最终发布目录

        Returns:
            SCons构建结果
        """
        # 收集依赖库的export_include_paths并合并到当前库
        dependency_export_paths = self._collect_dependency_export_paths(target)
        target.export_include_paths.extend(dependency_export_paths)

        # 为动态库创建专用的目录结构
        target_dir = os.path.join("out/intermediate/lib", target.name)
        target_intermediate_dir = os.path.join(target_dir, "objs")
        os.makedirs(target_intermediate_dir, exist_ok=True)

        # 先编译目标文件到指定目录（动态库使用.os文件）
        objects = []
        for source in target.sources:
            source_name = os.path.splitext(os.path.basename(source))[0]
            obj_path = os.path.join(target_intermediate_dir, f"{source_name}.os")
            obj = env.SharedObject(target=obj_path, source=source)
            objects.append(obj)

        # 动态库名称处理
        lib_name = target.name
        if not lib_name.startswith('lib'):
            lib_name = f'lib{lib_name}'

        # 中间文件路径，放在目标目录下
        intermediate_path = os.path.join(target_dir, lib_name)
        # 最终发布路径
        release_path = os.path.join(release_dir, lib_name)

        # 构建动态库到中间目录
        shared_lib = env.SharedLibrary(target=intermediate_path, source=objects)

        # 拷贝到发布目录
        copy_cmd = env.Command(release_path + '.so', intermediate_path + '.so', Copy("$TARGET", "$SOURCE"))

        # 返回所有相关节点
        return [shared_lib, copy_cmd]

    def _build_static_library(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        构建静态库

        Args:
            env: SCons环境
            target: 编译目标
            intermediate_dir: 中间文件目录
            release_dir: 最终发布目录

        Returns:
            SCons构建结果
        """
        # 收集依赖库的export_include_paths并合并到当前库
        dependency_export_paths = self._collect_dependency_export_paths(target)
        target.export_include_paths.extend(dependency_export_paths)

        # 为静态库创建专用的目录结构
        target_dir = os.path.join("out/intermediate/lib", target.name)
        target_intermediate_dir = os.path.join(target_dir, "objs")
        os.makedirs(target_intermediate_dir, exist_ok=True)

        # 先编译目标文件到指定目录
        objects = []
        for source in target.sources:
            source_name = os.path.splitext(os.path.basename(source))[0]
            obj_path = os.path.join(target_intermediate_dir, f"{source_name}.o")
            obj = env.Object(target=obj_path, source=source)
            objects.append(obj)

        # 处理static_libs中指定的依赖库（用于组合库功能）
        dependency_lib_files = []
        dependency_lib_nodes = []

        # 处理静态库依赖
        all_static_libs = target.static_libs[:]

        for lib_name in all_static_libs:
            dep_target = self.target_registry.get_target(lib_name)
            if dep_target and dep_target.target_type == TargetType.STATIC_LIBRARY:
                # 先构建依赖库
                dep_lib_nodes = self.build_target(dep_target.name)
                dependency_lib_nodes.extend(dep_lib_nodes)

                # 获取依赖库的静态库文件路径
                dep_lib_name = dep_target.name
                if not dep_lib_name.startswith('lib'):
                    dep_lib_name = f'lib{dep_lib_name}'
                dep_lib_path = os.path.join("out/intermediate/lib", dep_target.name, f"{dep_lib_name}.a")
                dependency_lib_files.append(dep_lib_path)

        # 静态库名称处理
        lib_name = target.name
        if not lib_name.startswith('lib'):
            lib_name = f'lib{lib_name}'

        # 中间文件路径，放在目标目录下
        intermediate_path = os.path.join(target_dir, lib_name)
        # 最终发布路径
        release_path = os.path.join(release_dir, lib_name)

        # 如果有依赖库需要合并，直接合并静态库
        if dependency_lib_files:
            final_lib_path = f"{intermediate_path}.a"

            # 创建一个自定义的action函数来合并静态库
            def merge_static_libraries(target, source, env):
                import subprocess
                import os
                import tempfile
                import time

                target_path = str(target[0])

                # 创建临时目录来提取所有目标文件
                with tempfile.TemporaryDirectory() as temp_dir:
                    all_objects = []

                    # 首先添加当前库的目标文件
                    current_obj_dir = os.path.join(temp_dir, 'current')
                    os.makedirs(current_obj_dir, exist_ok=True)

                    # 从source参数中处理目标文件和库文件
                    for src in source:
                        src_path = str(src)

                        if src_path.endswith('.o'):
                            # 这是目标文件，直接复制
                            if os.path.exists(src_path):
                                obj_name = os.path.basename(src_path)
                                temp_obj_path = os.path.join(current_obj_dir, obj_name)
                                subprocess.run(['cp', src_path, temp_obj_path], check=True)
                                all_objects.append(temp_obj_path)
                        elif src_path.endswith('.a'):
                            # 这是静态库文件，需要提取
                            # 等待文件存在（最多等待5秒）
                            for i in range(50):
                                if os.path.exists(src_path):
                                    break
                                time.sleep(0.1)

                            if os.path.exists(src_path):
                                # 使用绝对路径
                                abs_src_path = os.path.abspath(src_path)
                                # 为每个依赖库创建子目录
                                dep_dir = os.path.join(temp_dir, os.path.basename(src_path).replace('.a', ''))
                                os.makedirs(dep_dir, exist_ok=True)

                                # 提取依赖库中的目标文件
                                subprocess.run(['ar', 'x', abs_src_path], cwd=dep_dir, check=True)

                                # 收集提取的目标文件
                                for f in os.listdir(dep_dir):
                                    if f.endswith('.o'):
                                        all_objects.append(os.path.join(dep_dir, f))

                    # 创建新的静态库
                    if all_objects:
                        cmd = ['ar', 'rcs', target_path] + all_objects
                        subprocess.run(cmd, check=True)
                    else:
                        # 创建空的静态库
                        subprocess.run(['ar', 'rcs', target_path], check=True)

                return None

            # 准备依赖源文件列表 - 包含目标文件和库文件
            all_dependencies = dependency_lib_files[:] + objects

            static_lib = env.Command(
                target=final_lib_path,
                source=all_dependencies,  # 包含当前库的目标文件和依赖库文件
                action=merge_static_libraries
            )

            # 确保依赖库先构建
            for dep_node in dependency_lib_nodes:
                env.Depends(static_lib, dep_node)
        else:
            # 没有依赖库，按正常方式构建
            if not objects:
                # 创建一个空的目标文件
                empty_c_file = os.path.join(target_intermediate_dir, "empty.c")
                empty_obj_file = os.path.join(target_intermediate_dir, "empty.o")

                # 创建空的C文件
                env.Command(empty_c_file, [], "echo '// Empty file for library combination' > $TARGET")
                # 编译空的C文件
                empty_obj = env.Object(target=empty_obj_file, source=empty_c_file)
                objects = [empty_obj]

            # 构建静态库到中间目录
            static_lib = env.StaticLibrary(target=intermediate_path, source=objects)

        # 静态库不需要拷贝到发布目录，因为它不具备可执行能力
        # 静态库在编译时会被链接到可执行文件中

        # 返回静态库节点列表
        return [static_lib]

    def _build_object_files(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        构建目标文件

        Args:
            env: SCons环境
            target: 编译目标
            intermediate_dir: 中间文件目录
            release_dir: 最终发布目录

        Returns:
            SCons构建结果
        """
        objects = []
        for source in target.sources:
            source_name = os.path.splitext(os.path.basename(source))[0]
            obj_path = os.path.join(intermediate_dir, f"{source_name}.o")
            obj = env.Object(target=obj_path, source=source)
            objects.append(obj)

        return objects

    def clean_target(self, target_name: str):
        """
        清理指定目标

        Args:
            target_name: 目标名称
        """
        if target_name in self.built_targets:
            del self.built_targets[target_name]

    def clean_all(self):
        """清理所有目标"""
        self.built_targets.clear()

    def get_built_targets(self) -> List[str]:
        """
        获取已构建的目标列表

        Returns:
            已构建目标名称列表
        """
        return list(self.built_targets.keys())

    def _build_prebuilt_static_library(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        处理预编译静态库

        Args:
            env: SCons环境
            target: 编译目标
            intermediate_dir: 中间文件目录
            release_dir: 最终发布目录

        Returns:
            SCons构建结果
        """
        # 预编译库不需要实际构建，只需要验证文件存在
        if not os.path.exists(target.library_path):
            raise FileNotFoundError(f"预编译静态库文件不存在: {target.library_path}")

        # 创建prebuilt目录路径
        prebuilt_dir = "out/intermediate/prebuilt"
        marker_path = os.path.join(prebuilt_dir, f"prebuilt_{target.name}_marker")

        # 检查是否已经创建过这个Command
        cache_key = f"static_{target.name}"
        if cache_key in self.prebuilt_commands:
            return [self.prebuilt_commands[cache_key]]

        # 确保prebuilt目录存在
        if not hasattr(env, '_prebuilt_dir_created'):
            os.makedirs(prebuilt_dir, exist_ok=True)
            env._prebuilt_dir_created = True

        # 创建一个虚拟节点来表示这个预编译库
        # 这样其他目标可以依赖它，但实际上不会执行任何构建操作
        dummy_node = env.Command(marker_path, [],
            "echo 'Prebuilt static library: {0}' > $TARGET".format(target.library_path)
        )

        # 缓存Command
        self.prebuilt_commands[cache_key] = dummy_node

        return [dummy_node]

    def _build_proto_library(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        构建Protocol Buffers库

        Args:
            env: SCons环境
            target: 构建目标
            intermediate_dir: 中间文件目录
            release_dir: 发布目录

        Returns:
            构建结果列表
        """
        logging.info(f"Building proto library: {target.name}")

        # 获取proto支持工具
        proto_support = env.get('PROTO_SUPPORT')
        if not proto_support:
            raise RuntimeError("Proto support tool not loaded. Please add proto_support to SConstruct.")

        # 验证proto文件
        if not target.proto_files:
            logging.warning(f"No proto files specified for target: {target.name}")
            return []

        if not proto_support.validate_proto_files(target.proto_files):
            raise RuntimeError(f"Invalid proto files in target: {target.name}")

        # 创建目标专用的gensrc目录
        # 对于proto库，使用专门的gensrc目录而不是lib目录
        target_gensrc_dir = os.path.join("out/intermediate/lib", target.name)
        os.makedirs(target_gensrc_dir, exist_ok=True)

        # 生成proto源代码
        # 将proto_type映射为新的格式
        proto_type_mapping = {
            'full': 'cpp',
            'lite': 'cpp', 
            'min': 'c'
        }
        mapped_proto_type = proto_type_mapping.get(target.proto_type, 'cpp')
        
        generated_files = proto_support.generate_proto_sources(
            proto_files=target.proto_files,
            output_dir=target_gensrc_dir,
            proto_type=mapped_proto_type
        )

        # 更新目标的生成文件信息
        target.generated_sources = generated_files['sources']
        target.generated_headers = generated_files['headers']

        # 将生成的头文件目录添加到导出路径
        if target_gensrc_dir not in target.export_include_paths:
            target.export_include_paths.append(target_gensrc_dir)
        
        # 为每个生成的头文件添加其所在目录到导出路径
        for header_file in generated_files['headers']:
            header_dir = os.path.dirname(header_file)
            if header_dir not in target.export_include_paths:
                target.export_include_paths.append(header_dir)
                logging.info(f"Added header directory to export paths: {header_dir}")

        # 编译生成的源文件为对象文件
        objects = []
        proto_commands = generated_files.get('commands', [])
        
        # 调试信息：打印生成的源文件路径
        logging.info(f"Generated sources: {generated_files['sources']}")
        logging.info(f"Target gensrc dir: {target_gensrc_dir}")
        
        if generated_files['sources']:
            for i, source_file in enumerate(generated_files['sources']):
                logging.info(f"Processing source file: {source_file}")
                
                # 使用绝对路径确保正确找到源文件
                abs_source_file = os.path.abspath(source_file)
                
                # 计算对象文件路径，保持与源文件相同的子目录结构
                if os.path.isabs(source_file):
                    # 如果是绝对路径，计算相对于target_gensrc_dir的路径
                    try:
                        rel_source_path = os.path.relpath(source_file, target_gensrc_dir)
                    except ValueError:
                        # 如果无法计算相对路径，使用文件名
                        rel_source_path = os.path.basename(source_file)
                else:
                    # 如果是相对路径，直接使用
                    rel_source_path = source_file
                
                source_name = os.path.splitext(rel_source_path)[0]
                obj_path = os.path.join(target_gensrc_dir, f"{source_name}.o")
                
                logging.info(f"Object path: {obj_path}")
                logging.info(f"Source file for Object: {abs_source_file}")
                logging.info(f"Relative source path: {rel_source_path}")
                
                # 确保对象文件的目录存在
                os.makedirs(os.path.dirname(obj_path), exist_ok=True)
                
                # 创建Object构建规则，使用绝对路径
                obj = env.Object(target=obj_path, source=abs_source_file)
                
                # 确保Object依赖于对应的proto生成Command
                if i < len(proto_commands):
                    env.Depends(obj, proto_commands[i])
                
                objects.append(obj)
                
                # 添加生成文件所在的子目录到包含路径，确保编译时能找到头文件
                source_dir = os.path.dirname(abs_source_file)
                if source_dir not in env['CPPPATH']:
                    env.Append(CPPPATH=[source_dir])
                    logging.info(f"Added source directory to CPPPATH: {source_dir}")

        # 创建静态库
        static_lib_targets = []
        if objects:
            # 静态库路径 - 放在目标专用目录下
            static_lib_path = os.path.join(target_gensrc_dir, f"lib{target.name}.a")
            release_lib_path = os.path.join(release_dir, f"lib{target.name}.a")

            # 构建静态库
            static_lib = env.StaticLibrary(target=static_lib_path, source=objects)
            static_lib_targets.append(static_lib)

            # 复制静态库到发布目录
            copy_lib = env.Command(release_lib_path, static_lib_path, Copy("$TARGET", "$SOURCE"))
            static_lib_targets.append(copy_lib)

        # 复制头文件到发布目录
        install_targets = []
        if generated_files['headers']:
            for header_file in generated_files['headers']:
                header_name = os.path.basename(header_file)
                release_header = os.path.join(release_dir, header_name)

                # 创建复制命令
                install_target = env.Command(
                    target=release_header,
                    source=header_file,
                    action=Copy('$TARGET', '$SOURCE')
                )
                install_targets.append(install_target)

        # 记录构建结果
        self.built_targets[target.name] = {
            'type': target.target_type,
            'generated_sources': target.generated_sources,
            'generated_headers': target.generated_headers,
            'gensrc_dir': target_gensrc_dir,
            'export_include_paths': target.export_include_paths,
            'static_lib': static_lib_targets[0] if static_lib_targets else None
        }

        logging.info(f"Proto library built successfully: {target.name}")
        logging.info(f"  Generated sources: {len(target.generated_sources)}")
        logging.info(f"  Generated headers: {len(target.generated_headers)}")
        logging.info(f"  Static library: {static_lib_path if objects else 'None'}")
        logging.info(f"  Gensrc directory: {target_gensrc_dir}")

        # 返回所有生成的文件、静态库和安装目标
        all_targets = generated_files['sources'] + generated_files['headers'] + static_lib_targets + install_targets
        return all_targets

    def _build_prebuilt_shared_library(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        处理预编译动态库

        Args:
            env: SCons环境
            target: 编译目标
            intermediate_dir: 中间文件目录
            release_dir: 最终发布目录

        Returns:
            SCons构建结果
        """
        # 预编译库不需要实际构建，只需要验证文件存在
        if not os.path.exists(target.library_path):
            raise FileNotFoundError(f"预编译动态库文件不存在: {target.library_path}")

        # 获取库文件名
        lib_filename = os.path.basename(target.library_path)
        release_path = os.path.join(release_dir, lib_filename)

        # 创建prebuilt目录路径
        prebuilt_dir = "out/intermediate/prebuilt"
        marker_path = os.path.join(prebuilt_dir, f"prebuilt_{target.name}_marker")

        # 检查是否已经创建过这些Command
        cache_key = f"shared_{target.name}"
        copy_cache_key = f"copy_{target.name}"

        if cache_key in self.prebuilt_commands and copy_cache_key in self.prebuilt_commands:
            return [self.prebuilt_commands[cache_key], self.prebuilt_commands[copy_cache_key]]

        # 拷贝预编译动态库到发布目录
        copy_cmd = env.Command(release_path, target.library_path, Copy("$TARGET", "$SOURCE"))

        # 确保prebuilt目录存在
        if not hasattr(env, '_prebuilt_dir_created'):
            os.makedirs(prebuilt_dir, exist_ok=True)
            env._prebuilt_dir_created = True

        # 创建一个虚拟节点来表示这个预编译库
        # 这样其他目标可以依赖它，但实际上不会执行任何构建操作
        dummy_node = env.Command(marker_path, [],
            "echo 'Prebuilt shared library: {0}' > $TARGET".format(target.library_path)
        )

        # 缓存Command
        self.prebuilt_commands[cache_key] = dummy_node
        self.prebuilt_commands[copy_cache_key] = copy_cmd

        return [dummy_node, copy_cmd]

    def _build_header_library(self, env, target: BuildTarget, intermediate_dir: str, release_dir: str):
        """
        构建头文件库

        Args:
            env: SCons环境
            target: 编译目标
            intermediate_dir: 中间文件目录
            release_dir: 发布目录

        Returns:
            SCons构建结果
        """
        # 头文件库不需要编译或拷贝文件，只是为了其他模块编译时使用
        # 创建一个虚拟目标来表示头文件库已构建完成
        marker_path = os.path.join(intermediate_dir, f"{target.name}.header_lib")
        os.makedirs(intermediate_dir, exist_ok=True)

        # 创建虚拟目标，不依赖任何源文件
        dummy_node = env.Command(marker_path, [],
            "echo 'Header library built: {0}' > $TARGET".format(target.name)
        )

        return [dummy_node]